//
// Created by Scave on 2025/8/25.
//

#include "StandardRenderSystem.h"
#include "component/BasicComponents.h"
#include "component/InternalComponent.h"
#include "EntityUtil.h"

NS_RIDER_BEGIN

    void StandardRenderSystem::configure(EntityManager& entities, EventManager& events) {

    }

    void StandardRenderSystem::update(EntityManager& entities, EventManager& events, TimeDelta dt) {
        std::vector<LightItem> lights;
        CollectLights(entities, lights);
        Entity root_entity = EntityUtil::FindRootEntity(entities);
        ComponentHandle<RenderNodes> nodes = root_entity.component<RenderNodes>();
        Camera* camera = nullptr;
        if (root_entity.has_component<Camera>()) {
            camera = root_entity.component<Camera>().get();
        }
        for (auto entity: entities.entities_with_components<MeshRenderModel>()) {
            ComponentHandle<MeshRenderModel> model = entity.component<MeshRenderModel>();
            SMART_PTR<StandardRenderNode> node = MAKE_SMART_PTR<StandardRenderNode>();
            node->name = entity.component<EntityIdentifier>()->name;
            node->lights = lights;
            node->mesh = model->mesh;
            node->material = model->material;

            node->mtx_model = ComputeModelMatrix(entity);
            node->ambient_color = root_entity.component<SceneConfig>()->ambient_color;
            if (camera != nullptr) {
                node->camera_pos = camera->position;
            }
            nodes->PushNode(LayerMask::Object, node);
        }
        nodes->SetLayerCamera(LayerMask::Object,
                              ComputeViewMatrix(camera), ComputeProjectionMatrix(camera));
    }

    Mat4 StandardRenderSystem::ComputeModelMatrix(Entity& entity) {
        Mat4 result;
        auto transform = entity.component<Transform>();
        result.SRT(transform->scale, transform->rotation, transform->translation);
        return result;
    }

    Mat4 StandardRenderSystem::ComputeViewMatrix(Camera* camera) {
        if (camera == nullptr) {
            return {};
        }
        Mat4 result;
        result.LookAt(camera->position, camera->target, camera->up_axis);
        return result;
    }

    Mat4 StandardRenderSystem::ComputeProjectionMatrix(Camera* camera) {
        if (camera == nullptr) {
            return {};
        }
        Mat4 result;
        if (camera->projection_type == ProjectionType::Perspective) {
            result.Perspective(camera->field_of_view, float(camera->view_port.w) / float(camera->view_port.h),
                               camera->near_clip_plane, camera->far_clip_plane);
        } else {
            result.Orthographic(-1, 1, -1, 1, camera->near_clip_plane, camera->far_clip_plane, 0);
        }
        return result;
    }

    void StandardRenderSystem::CollectLights(EntityManager& entities, std::vector<LightItem>& lights) {
        for (Entity entity: entities.entities_with_components<Light>()) {
            LightItem light;
            light.type = entity.component<Light>()->type;
            light.strength = entity.component<Light>()->strength;
            light.position = entity.component<Transform>()->translation;

            Quaternion q = entity.component<Transform>()->rotation;
            light.direction = q.ToDirection();

            light.color = entity.component<Light>()->color;
            light.range = entity.component<Light>()->range;
            light.attenuation = entity.component<Light>()->attenuation;
            light.spotAngle = entity.component<Light>()->spotAngle;

            lights.push_back(light);
        }
    }

NS_RIDER_END
